/**
在 Webpack 中，Scope Hoisting（作用域提升）是一种优化技术，旨在通过将模块的代码合并到一个函数作用域中，从而减少函数调用的开销和提升执行效率。这种技术可以显著减小最终打包文件的体积，并提高加载和执行速度。
  1. 什么是 Scope Hoisting？
  Scope Hoisting 是将多个模块的代码合并到一个作用域内，从而减少模块之间的开销和函数调用。通过这种方式，Webpack 能够生成更小的代码，并提高运行时的性能。

  2. Scope Hoisting 的工作原理
  在 Webpack 中，每个模块通常会被包装在一个函数中，这样可以隔离模块之间的作用域。Scope Hoisting 通过将这些函数合并为一个函数来减少函数调用次数，从而提高性能。

  3. 启用 Scope Hoisting
  Scope Hoisting 在 Webpack 4 及以上版本中默认启用，但只有在使用 ES6 模块语法（`import` 和 `export`）时才能发挥作用。以下是一些步骤来确保启用 Scope Hoisting：

   1. 使用 ES6 模块
  确保你的代码使用 ES6 的模块语法，因为 Scope Hoisting 依赖于模块的静态结构。

   示例：

  ```javascript
  // moduleA.js
  export const greet = () => {
      console.log('Hello from Module A');
  };

  // moduleB.js
  import { greet } from './moduleA';

  greet();
  ```

   2. 设置生产模式
  在 Webpack 配置中，将模式设置为 `production`。在生产模式下，Webpack 会自动启用许多优化功能，包括 Scope Hoisting。

  ```javascript
  module.exports = {
      mode: 'production',
      // 其他配置...
  };
  ```

  4. 注意事项
  - 模块语法: 确保使用 ES6 模块语法，因为 Scope Hoisting 只对这种类型的模块有效。
  - 模块数量: 当模块数量较多时，Scope Hoisting 的效果会更加明显。在大型项目中，合理使用 Scope Hoisting 可以显著提高性能。
  - 测试: 在启用 Scope Hoisting 后，进行充分的测试以确保应用的功能没有受到影响。

  总结
  Scope Hoisting 是 Webpack 中一种有效的优化技术，通过将多个模块的代码合并到一个作用域中，减少函数调用的开销，从而提升执行效率和减少代码体积。通过使用 ES6 模块和设置生产模式，开发者可以充分利用 Scope Hoisting 的优势，优化项目的构建输出。希望这个总结对你理解 Webpack 中的 Scope Hoisting 有所帮助！
 */
const path = require("path");
const glob = require("glob");
const TerserPlugin = require("terser-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
// const CSSMinimizerPlugin = require("css-minimizer-webpack-plugin");
const { PurgeCSSPlugin } = require("purgecss-webpack-plugin");
const webpack = require("webpack");

/**
  [
    'src\\main.js',
    'src\\demo.js',
    'src\\abc.js',
    'src\\utils\\foo.js',
    'src\\utils\\bar.js',
    'src\\ts\\math.ts',
    'src\\router\\category.js',
    'src\\router\\about.js',
    'src\\react\\App.jsx',
    'src\\demo\\parse-lyric.js',
    'src\\demo\\math.js',
    'src\\css\\style.css'
  ]
 */
console.log(
  glob.sync(`${path.resolve(__dirname, "../src")}/**/*`, { nodir: true })
); // 获取所有文件

module.exports = {
  mode: "production",
  optimization: {
    chunkIds: "deterministic", // 生成文件名时使用确定的文件名
    runtimeChunk: {
      name: "runtime", // 将runtime相关的代码单独打包
    },
    splitChunks: {
      // 分包配置
      chunks: "all", // 对所有模块都进行分割
      minSize: 10, // 分割的模块最小为10kb
      // 自己对需要进行拆包的内容进行分包
      cacheGroups: {
        utils: {
          test: /utils/,
          filename: "js/[id]_utils.js",
        },
        vendors: {
          // /node_modules/
          // window上面 /\
          // mac上面 /
          test: /[\\/]node_modules[\\/]/,
          filename: "js/[id]_vendors.js",
        },
      },
    },
    minimize: true, // 是否使用压缩
    // 压缩配置
    minimizer: [
      // JS压缩的插件: TerserPlugin
      new TerserPlugin({
        extractComments: false, // 不将注释提取到单独的文件中
        terserOptions: {
          compress: {
            arguments: true, // 移除console.log
            unused: true, // 移除未使用的代码
          },
          mangle: true, // 压缩变量名
          // toplevel: true, // 移除未使用的变量
          keep_fnames: true, // 保留函数名
        },
      }),
      // CSS压缩的插件: CSSMinimizerPlugin
      // new CSSMinimizerPlugin({
      //   // parallel: true, // 开启多进程
      // }),
    ],
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: "css/[name].css",
      chunkFilename: "css/[name]_chunk.css",
    }),
    // 对css进行treeshaking
    new PurgeCSSPlugin({
      paths: glob.sync(`${path.resolve(__dirname, "../src")}/**/*`, {
        nodir: true, // 不包括文件夹
      }),
      // safelist表示: 哪些类名不能被移除
      safelist: function () {
        return {
          standard: ["body"],
        };
      },
    }),
    new webpack.optimize.ModuleConcatenationPlugin(), // 作用域提升 Scope Hoisting
  ],
};
